package com.fingard.dsp.bank.directbank.boc01.receiptpro;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.fingard.constant.Format;
import com.fingard.diagnostics.LogHelper;
import com.fingard.dsp.bank.dbobj.receipt.ReceiptData;
import com.fingard.dsp.bank.dbobj.receipt.ReceiptDataHelper;
import com.fingard.dsp.bank.dbobj.updownfile.DownFileHelper;
import com.fingard.dsp.bank.dbobj.updownfile.DownFileRecord;
import com.fingard.dsp.bank.directConfig.FtpSet;
import com.fingard.dsp.bank.directConfig.ReceiptProConfig;
import com.fingard.dsp.bank.directConfig.ReceiptSet;
import com.fingard.dsp.bank.directConfig.TaskTimerSet;
import com.fingard.dsp.bank.directbank.boc01.BOC01Base;
import com.fingard.dsp.bank.sepro.ReceiptPro;
import com.fingard.dsp.task.DelayCounter;
import com.fingard.dsp.task.command.SyncReceipt;
import com.fingard.generalobj.ExecResponse;
import com.fingard.io.FileCheckHelper;
import com.fingard.io.FileHelper;
import com.fingard.net.FtpReceiver;
import com.fingard.net.MixFtp;
import com.fingard.text.StringHelper;
import com.fingard.util.DateHelper;
import com.fingard.util.ZipHelper;

import com.fingard.FGBiz;

/**中行下载回单任务*/
public class BOC01TaskReceiptPro extends BOC01Base {
	
	private String logCode = "BOC01"+File.separator+"TaskReceiptPro";
	private TaskTimerSet timerSet;
	private ReceiptProConfig proConfig;
	//private boolean byLocalhost;
	
	private static DelayCounter delayCounter = new DelayCounter(45, 2);//最大延时45分钟，按平方计算，即4次=4*4=16分钟
	public static void resetDelayCounter(){
		delayCounter.resetZeroCount();
	}
	
	public void downReceipt(TaskTimerSet pTimerSet){
		try {
			timerSet = pTimerSet;
			
			proConfig = ReceiptPro.getReceiptProConfig();
			//byLocalhost = false;
			downFiles();
		
		} catch (Exception e) {
			FGBiz.logTrace.exception(logCode, e);
		}
	}

	/**下载回单文件，
	 * 通过接口：逐笔电子回单下载(b2e0500)或者电子回单下载(b2e0377)，提交中行后，中行产生压缩包，上传至该sftp或保存的前置机本地，
	 * dsp记录需下载的文件到表DOWNFILE，
	 * 本次任务遍历DOWNFILE未下载的记录，逐个下载并解析（取本地，或者ftp/sftp）*/
	private void downFiles(){
		//HashMap<String, MixFtp> mapMixFtp = new HashMap<String, MixFtp>();
		try{
			
			if(delayCounter.isDelay()){
				return;
			}
			
			int beginMonthCount = timerSet.getParamAsInt("beginMonthCount", -1);
			int endMonthCount = timerSet.getParamAsInt("endMonthCount", 0);
			if(beginMonthCount>endMonthCount){
    			FGBiz.logTrace.info(logCode, "开始天数大于结束天数，两者互换");
    			int chg = beginMonthCount;
    			beginMonthCount = endMonthCount;
    			endMonthCount = chg;
    		}
			
			int needDownCount = 0;//需要下载的记录总数
			int succDownCount = 0;//下载成功的记录数
			Date nowDay = new Date();
			for(int mthCount=beginMonthCount; mthCount<=endMonthCount; mthCount++){
				//按日循环，取DOWNFILE表中的记录
    			Date eachDay = DateHelper.addMonths(nowDay, mthCount);
    			DownFileHelper dfHelper = null;
    			try{
    				dfHelper = new DownFileHelper(bankFront.tenant, eachDay);
    				//获取该前置机该分区所有待下载的文件
    				HashMap<Long, Integer> uridList = dfHelper.getAllNeedDownList(bankFront.bankCode, bankFront.code);
        			if(uridList != null && uridList.size() > 0){
        				needDownCount += uridList.size();
        				//遍历每个需要下载的文件
        				Iterator<Map.Entry<Long, Integer>> it = uridList.entrySet().iterator();
        				while (it.hasNext()) {
        					Map.Entry<Long, Integer> eachEntry = it.next();
        					long urid = eachEntry.getKey();
        					//逐个执行
        					//取得要下载的文件记录
        					DownFileRecord fileRdForUpd = dfHelper.loadFromDbByUrid(urid);
        					if(fileRdForUpd!=null){
        						ReceiptSet receiptSet = this.getBankReceiptConfig().getReceiptSetByAct(fileRdForUpd.ownAct, bankFront);
	        					fileRdForUpd.downTime = new Date();
	        					ExecResponse resp = downEachRdByFileRecord(dfHelper, receiptSet, fileRdForUpd);
	        					if(resp.isSucceed){
	        						succDownCount++;
	        						fileRdForUpd.downState = "2";
	        						fileRdForUpd.downInfo = resp.getResultAsString();
	        					}else{
	        						fileRdForUpd.downState = "3";
	        						fileRdForUpd.downInfo = resp.logMsg;
	        						FGBiz.logTrace.error(logCode, "urid为"+urid+"的记录，"+resp.logMsg);
	        					}
	        					int rowsAff = dfHelper.updateDownState(fileRdForUpd);
	        					if(rowsAff<1){
	        						FGBiz.logTrace.error(logCode, "urid:"+urid+"的记录，更新行数："+rowsAff);
	        					}
        					}else{
        						FGBiz.logTrace.error(logCode, "urid:"+urid+"的记录，已被移除");
        					}
        				}
        			}else{
        				FGBiz.logTrace.info(logCode, "取"+Format.Date6YearMonth.format(eachDay)+"线路"+bankFront.bankCode+"前置机"+bankFront.code+"的待下载文件记录为空");
        			}
    			}catch(Exception ex){
    				FGBiz.logTrace.exception(logCode, ex);
                }finally{
                	if(dfHelper!=null){
                		dfHelper.close();
                	}
                }
			}
			FGBiz.logTrace.info(logCode, "本次需下载"+needDownCount+"个，下载成功"+succDownCount+"个");
			if(succDownCount == 0){
				delayCounter.increaseZeroCount();
				FGBiz.logTrace.info(logCode, "成功个数为0，下次执行将增加延时"+delayCounter.getDelayMinutes()+"分钟");
			}else{
				delayCounter.resetZeroCount();
				SyncReceipt.resetDelayCounter();//同步任务重新计数延时
			}
		}catch(Exception ex){
			FGBiz.logTrace.exception(logCode, ex);
		}finally{
			/*
			Iterator<Map.Entry<String, MixFtp>> itSet = mapMixFtp.entrySet().iterator();
			while (itSet.hasNext()) {
				Map.Entry<String, MixFtp> eachIt = itSet.next();
				MixFtp eachMixFtp = eachIt.getValue();
				if(eachMixFtp!=null){
					try {
						eachMixFtp.disconnect();
						eachMixFtp = null;
					} catch (IOException e) {
						FGBiz.logTrace.exception(logCode,e);
					}
				}
			}
			*/
		}
	}
	
	/**根据URID，进行下载及处理，返回保存成功条数
	 * @throws ParseException 
	 * @throws SQLException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @throws IOException */
	private ExecResponse downEachRdByFileRecord(DownFileHelper dfHelper, ReceiptSet pReceiptSet, DownFileRecord pFileRd) throws IllegalArgumentException, IllegalAccessException, SQLException, ParseException, IOException{
		
		ExecResponse retResp = new ExecResponse();
		Date bzDate = pFileRd.getBusDate();
		//按月建目录存下载的压缩文件
		String saveDirPath = proConfig.getSaveSubDir(reqHeader, bzDate) + File.separator + pFileRd.busDate;
		//执行删除临时文件
		String delLog = ReceiptPro.deleteTmpFile(saveDirPath);
		if(StringHelper.hasAnyChar(delLog)){
			FGBiz.logTrace.info(logCode, "删除临时文件：\r\n" + delLog);
		}
		
		String subDirByFp = pFileRd.busDate + File.separator + pFileRd.ownAct + File.separator + StringHelper.trimFileExt(pFileRd.filePath);
		
		String localDirPath = proConfig.getSaveSubDir(reqHeader, bzDate) + File.separator + subDirByFp;
		String relativeSaveDir = proConfig.getRelativeSaveDir(reqHeader, bzDate) + File.separator + subDirByFp;
		
		String localTrgFile = saveDirPath + File.separator + pFileRd.filePath;
		
		
		
		retResp.setResult("下载至"+localTrgFile);
		
		boolean isSucc = false;
		if(FileHelper.existFile(localTrgFile) && FileHelper.existFile(localDirPath)){
			FGBiz.logTrace.info(logCode, "本地已经存在文件"+localTrgFile+"，不需再下载。\r\n如果要重新从ftp上下载该回单压缩文件，需删除目录"+localDirPath+"，\r\n再删除文件"+localTrgFile+"。");
			isSucc = true;
		}
		String timePostfix = Format.Time9Format.format(new Date());
		//先保存到临时文件，正常解压后再重命名
		String localTmpFilePath = localTrgFile + "."+ timePostfix +".tmp";
		String tmpDecompressDir = localTrgFile + "."+ timePostfix + ".unzip";
		
		ReceiptDataHelper receiptHelper = null;//回单数据保存类，分区分表
		MixFtp mixFtp = null;
		try{
			if(!isSucc){
				ExecResponse respDown = null;
				String downFromForLog = "";
				if("localhost".equalsIgnoreCase(pReceiptSet.receiptDownloadType)){//本地目录
					downFromForLog = "目录"+bankFront.bankReceiptMainDir;
					respDown = downEachFileByLocalhost(pFileRd, localTmpFilePath);
				}else{//ftp/sftp
					if(pReceiptSet.ftpSet!=null){
						downFromForLog = pReceiptSet.ftpSet.ftpType + "服务" + pReceiptSet.ftpSet.serverIP + ":" + pReceiptSet.ftpSet.port;
						mixFtp = new MixFtp(pReceiptSet.ftpSet);
						//调用ftp/sftp下载
						respDown = downEachFileByFtp(mixFtp, pFileRd, localTmpFilePath);
						if(respDown.isSucceed == false){
							FGBiz.logTrace.error(logCode, "下载失败，"+pReceiptSet.ftpSet.ftpType+"服务"+pReceiptSet.ftpSet.serverIP+":"+pReceiptSet.ftpSet.port+"，下载目录："+pReceiptSet.ftpSet.downDir);
						}
						mixFtp.disconnect();//尽快关闭释放
						mixFtp = null;
					}else{
						downFromForLog = "ftp/sftp";
						respDown = new ExecResponse();
						respDown.isSucceed = false;
						respDown.logMsg = "未配置回单ftp设置";
					}
					//ArrayList<String> fnames = mixFtp.listNames(ftpSet.downDir);
					//FGBiz.logTrace.debug(logCode, ftpSet.downDir+"下的文件或目录有：" + StringHelper.join(",", fnames));
				}
				if(respDown.isSucceed){
					boolean isZip = false;
					String receiptTrnCode = this.getBankConfig().getValueAsString("receiptTrnCode").toLowerCase();
					//回单接口b2e0377,b2e0500，二选一，默认b2e0500（逐笔）
					if(!"b2e0377".equals(receiptTrnCode)){
						receiptTrnCode = "b2e0500";
						isZip = true;
					}
					if(isZip){
						//b2e0500 是zip文件
						File depressDir = new File(tmpDecompressDir);
						if(!depressDir.exists()){
		            		depressDir.mkdirs();
		            	}
						FGBiz.logTrace.debug(logCode, "解压至：[" + tmpDecompressDir + "]");
		                ZipHelper.unzipFile(localTmpFilePath, tmpDecompressDir);
		                FGBiz.logTrace.debug(logCode, "执行解压结束");
		                //校验解压之后的目录是否正常
		                if (depressDir.exists()) {
		                    File[] deFiles = depressDir.listFiles();
		                    boolean isPdfChked = false;
	                    	//校验通过后，需重命名的
	                    	File needRenameDir = depressDir;
	                    	File hitDir = depressDir;//临时变量，遍历中赋值
	                    	for(int i=0;i<10;i++){//存在多层目录，找到有html文件的目录，最多循环10次，即10层目录
	                    		if(deFiles != null && deFiles.length > 0){
	                    			needRenameDir = hitDir;
	                				isPdfChked = FileCheckHelper.existExtFile(deFiles, "pdf", "");//判断是否存在pdf文件
	                				if(isPdfChked){
	                					break;
	                				}
	                    		}
	                    		if (deFiles != null && deFiles.length > 0) {
	                    			hitDir = deFiles[0];
	                    			deFiles = hitDir.listFiles();
	                    		}
	                    	}
	                    	if(isPdfChked){
	                    		FGBiz.logTrace.info(logCode, needRenameDir.getAbsolutePath()+"重命名为"+localDirPath);
	                        	File destDir = new File(localDirPath);
	                        	boolean renamed = FileHelper.renameFileOrDir(needRenameDir, destDir);
	                        	if(renamed && destDir.exists()){//重命名目录成功
	                        		//重命名zip文件
	                        		FGBiz.logTrace.info(logCode, localTmpFilePath+"重命名为"+localTrgFile);
	                        		File tmpZip = new File(localTmpFilePath);
	                        		File destZip = new File(localTrgFile);
	                        		if(destZip.exists()){
	                        			destZip.delete();
	                        		}
	                        		boolean rezip = FileHelper.renameFileOrDir(tmpZip, destZip);
	                        		if(rezip && destZip.exists()){
	                        			isSucc = true;
	                        		}else{
	                        			retResp.logMsg = "重命名失败：" + localTmpFilePath + "重命名为" + localTrgFile;
	                        			FGBiz.logTrace.error(logCode, retResp.logMsg);
	                        		}
	                        	}else{
	                        		retResp.logMsg = "重命名失败：" + needRenameDir.getName()+"重命名为"+localDirPath;
	                        		FGBiz.logTrace.error(logCode, retResp.logMsg);
	                        	}
	                        }else{
	                        	retResp.logMsg = "解压后文件夹校验不通过，未找到pdf文件";
	                        	FGBiz.logTrace.error(logCode, retResp.logMsg);
	                        }
		                }else{
		                	retResp.logMsg = "不存在解压目录："+tmpDecompressDir;
		                	FGBiz.logTrace.error(logCode, retResp.logMsg);
		                }
					}else{
						retResp.logMsg = "非b2e0500接口，逻辑待实现";
	                	FGBiz.logTrace.error(logCode, retResp.logMsg);
					}
				}else{
					FGBiz.logTrace.error(logCode, "从"+downFromForLog+"下载回单文件失败："+respDown.logMsg+"\r\n可能原因：文件不存在、ftp/sftp配置有误、下载路径配置有误");
					retResp.logMsg = respDown.logMsg;
				}
			}
			if(isSucc){//文件已下载并正常解压，遍历文件进行处理
				int sCount = 0;
				File rDir = new File(localDirPath);
				if(!rDir.exists()){
					retResp.logMsg = "回单解压目录"+localDirPath+"不存在，待下次轮询重新处理";
					return retResp;
				}
				File[] receiptFiles = rDir.listFiles();
				for (File receiptFile : receiptFiles) {
					String eachName = receiptFile.getName();
					if(!eachName.toLowerCase().endsWith(".pdf")){
						FGBiz.logTrace.info(logCode, eachName+"非pdf文件，过滤");
						continue;
					}
					
					String[] receiptFileName = StringHelper.trimFileExt(eachName).split("\\+");
					if(receiptFileName.length<3){
						FGBiz.logTrace.info(logCode, eachName+"按“+”拆分后格式有误，拆分后数组长度小于3");
						continue;
					}
					ReceiptData eachData = new ReceiptData();
					eachData.downInfo = "";
                    String actNum = receiptFileName[1];
                    if(!pFileRd.ownAct.equals(actNum)){
                    	eachData.downInfo = "提取的账号"+actNum+"不符合预期";
                    	FGBiz.logTrace.error(logCode, eachName + eachData.downInfo + pFileRd.ownAct);
                    }
                    String actCur = getBankConfig().getMapValueByKey("elereceiptAccountInfo", pFileRd.ownAct);
                    if (StringHelper.isNullOrEmpty(actCur)) {
                        actCur = "1";
                    }
                    String bkBusDate = receiptFileName[0];
                    if(!bkBusDate.equals(pFileRd.busDate+"")){
                    	eachData.downInfo = StringHelper.joinNotEmpty("；", "提取的日期"+bkBusDate+"不符合预期");
                    	FGBiz.logTrace.error(logCode, eachName+eachData.downInfo+pFileRd.busDate);
                    }
                    eachData.istNbr = receiptFileName[2];
                    eachData.localFile = relativeSaveDir+File.separator + eachName;
                    eachData.srcFile = eachName;
                    eachData.busRef = receiptFileName[2];
                    eachData.receiptNo = receiptFileName[2];
                    eachData.bank = "104";
                    eachData.srcSys = "BOC01";
                    if(bkBusDate.length() == 8){
                    	eachData.busDate = Integer.parseInt(bkBusDate);
                    }else{
                    	eachData.busDate = pFileRd.busDate;
                    }
                    eachData.ownAct = pFileRd.ownAct;
                    eachData.cur = actCur;
                    eachData.downState = "2";
                    eachData.downTime = new Date();
                    eachData.downInfo = StringHelper.subStringByGBKByte(eachData.downInfo, 128);
                    if(receiptHelper == null){
                    	receiptHelper = new ReceiptDataHelper(reqHeader.tenant, eachData.getBusDate());
                    }
                    int inRe = receiptHelper.insertIfNotExist(eachData);
                    if(inRe>0){
                    	sCount++;
                    }else{
                    	FGBiz.logTrace.info(logCode, eachData.receiptNo+"写入数据库，影响行数："+inRe);
                    }
				}
				if(sCount>0){
					retResp.isSucceed = true;
					FGBiz.logTrace.info(logCode, "账号"+pFileRd.ownAct+"日期"+pFileRd.busDate+"成功保存"+sCount+"条回单数据");
				}else{
					retResp.logMsg = "保存回单数据记录数："+sCount;
				}
			}
		}catch(Exception ex){
			retResp.logMsg = LogHelper.getStackTrace(ex);
			FGBiz.logTrace.exception(logCode, ex);
		}finally{
			if(receiptHelper!=null){
				receiptHelper.close();
			}
			if(mixFtp !=null){
				mixFtp.disconnect();
			}
            try{
            	FGBiz.logTrace.info(logCode, "删除临时目录："+tmpDecompressDir);
            	FileHelper.deleteRecursive(tmpDecompressDir);
            }catch(Exception e){
            	FGBiz.logTrace.exception(logCode, e);
            }
            try{
            	FGBiz.logTrace.info(logCode, "删除临时文件："+localTmpFilePath);
            	FileHelper.deleteFileIfExists(localTmpFilePath);
            }catch(Exception e){
            	FGBiz.logTrace.exception(logCode, e);
            }
		}
		return retResp;
	}
	
	
	
	/**从本地目录复制*/
	private ExecResponse downEachFileByLocalhost(DownFileRecord pFileRd, String pLocalTrgFile) throws IOException{
		ExecResponse resp = new ExecResponse();
		
		String mDir = bankFront.bankReceiptMainDir;
		String filePath = StringHelper.trimEndFileSp(mDir)+File.separator+StringHelper.trimStartFileSp(pFileRd.filePath);
		File srcFile = new File(filePath);
		if(srcFile.exists()){
			Date lastMdDate = new Date(srcFile.lastModified());
            double diffSecs = DateHelper.getDifferSecs(new Date(), lastMdDate);
            if (diffSecs < 10) {//小于10秒的先不传
            	resp.logMsg = "回单文件最后修改时间离当前时间小于10秒，暂不获取："+filePath;
            }else{
            	File destFile = new File(pLocalTrgFile);
    			FileHelper.copyFile(srcFile, destFile);
    			if(destFile.exists()){
    				resp.isSucceed = true;
    			}else{
    				resp.logMsg = "复制文件失败：复制"+filePath+"，至"+pLocalTrgFile;
    			}
            }
		}else{
			resp.logMsg = "不存在文件"+filePath+"，可能银行还未生成";
		}
		return resp;
	}
	
	/**从ftp下载*/
	private ExecResponse downEachFileByFtp(MixFtp pMixFtp, DownFileRecord pFileRd, String pLocalTrgFile){
		ExecResponse resp = new ExecResponse();
		
		try {
			FtpReceiver ftpRec = pMixFtp.downloadFileFromDir(pMixFtp.ftpSet.downDir, pFileRd.filePath, pLocalTrgFile);
			if(ftpRec.isCompleted){
				resp.isSucceed = true;
			}else{
				resp.logMsg = ftpRec.connMsg;
			}
		} catch (IOException e) {
			resp.logMsg = LogHelper.getStackTrace(e);
			FGBiz.logTrace.exception(logCode,e);
		}
		
		return resp;
	}
}
